package com.epam.database;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.epam.util.PropertiesReaderWithClassLoader;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ConnectionPool {
	private static final Logger LOGGER = LoggerFactory
			.getLogger(ConnectionPool.class);

	public static final int DEFAULT_POOL_SIZE = 10;
	/** single instance */
	private static ConnectionPool instance;
	/** free connections queue */
	private BlockingQueue<Connection> connectionQueue;

	private ConnectionPool(String driver, String url, String user,
			String password, int poolSize) throws ClassNotFoundException,
			SQLException {
		Class.forName(driver);
		connectionQueue = new ArrayBlockingQueue<Connection>(poolSize);
		for (int i = 0; i < poolSize; i++) {
			Connection connection = DriverManager.getConnection(url, user,
					password);
			connectionQueue.offer(connection);
		}
	}

	public static synchronized ConnectionPool getInstance() {
		if (instance == null) {
			try {
				String driver = PropertiesReaderWithClassLoader.getProperties(
						"initpool.properties").get("database.driver");
				String url = PropertiesReaderWithClassLoader.getProperties(
						"initpool.properties").get("database.url");
				String user = PropertiesReaderWithClassLoader.getProperties(
						"initpool.properties").get("database.user");
				String password = PropertiesReaderWithClassLoader
						.getProperties("initpool.properties").get(
								"database.password");
				if (!isDatabaseByUrl(url)) {
					url = PropertiesReaderWithClassLoader.getProperties(
							"initpool.properties").get("database.create.url");					
				}			
				// Trying to create pool of connections...
				instance = new ConnectionPool(driver, url, user, password,
						DEFAULT_POOL_SIZE);
				LOGGER.info("Connection pool  initialized");
			} catch (ClassNotFoundException e) {
				LOGGER.warn("Failed to initialize the connection pool");
				throw new RuntimeException(e);
			} catch (Exception e) {
				LOGGER.info(e.getMessage()); 
			}
		}
		return instance;
	}

	public Connection takeConnection() {
		Connection connection = null;
		try {
			connection = connectionQueue.take();
			LOGGER.info("Connection was take");
		} catch (InterruptedException e) {
			LOGGER.warn("Free connection waiting interrupted");
			// Returned `null` connection", e
		}
		return connection;
	}

	public void returnConnection(Connection connection) {
		try {
			if (!connection.isClosed()) {
				if (!connectionQueue.offer(connection)) {
					LOGGER.warn("Connection not added. Possible `leakage` of connections");
				}
			}
		} catch (SQLException e) {
			LOGGER.warn("Connection not returned", e);
		}
	}

	public static void dispose() throws SQLException {
		if (instance != null) {
			instance.clearConnectionQueue();
			instance = null;
			LOGGER.info("Connection pool succesfully disposed");
		}
	}

	private void clearConnectionQueue() throws SQLException {
		Connection connection;
		while ((connection = connectionQueue.poll()) != null) {
			if (!connection.getAutoCommit()) {
				connection.commit();
			}
			connection.close();
		}
	}

	private static boolean isDatabaseByUrl(String url) {
		String path = url.substring(8);
		path = path + ".h2.db";		
		File file = new File(path);
		if (file.exists() && file.isFile()) {
			return true;
		} else {
			return false;
		}
	}

}
